﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using HtmlAgilityPack;

namespace AutoDownload
{
    public partial class Crawler : Form
    {
        private readonly List<string[]> linkList = new List<string[]>();
        private readonly StatusInfo statusInfo = new StatusInfo();
        private int totalCount = 0;

        public Crawler()
        {
            InitializeComponent();
        }

        private void loadButton_Click(object sender, EventArgs e)
        {
            if (reportLocationText.Text == "")
            {
                messageText.AppendText("Hãy chọn vị trí lưu report.");
                return;
            }

            if (listCombo.Items.Count == 0)
            {
                messageText.AppendText("Hãy mở danh sách link và thư mục");
                return;
            }

            progressBar.Visible = true;
            messageText.Clear();
            messageText.AppendText("Started at " + DateTime.Now.ToString() + System.Environment.NewLine);
            bgWorker.RunWorkerAsync(reportLocationText.Text);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            StreamWriter fileWriter = null;
            try
            {
                totalCount = 0;
                for (var y = 0; y < linkList.Count; y++)
                {
                    int page = 1, count = 0;
                    HtmlNodeCollection trList;

                    var titleDict = new StringDictionary(); // danh sách các tựa sách, key là title, value là stt
                    var nameDict = new StringDictionary();  
                    var duplicateDict = new NameValueCollection();  // danh sách trùng, key là title, value là collection tên file
                    var nameList = new StringCollection();  // danh sách tên file, key là tên, value là
                    var row = linkList[y];
                    var currentPath = Path.GetDirectoryName(e.Argument.ToString()) + @"\" + row[1];

                    if (!Directory.Exists(currentPath))
                        Directory.CreateDirectory(currentPath);

                    fileWriter = new StreamWriter(currentPath + @"\" + Path.GetFileName(e.Argument.ToString())
                                                  , false, Encoding.UTF8);

                    lock (statusInfo)
                    {
                        statusInfo.CurrentIndex = y;
                        bgWorker.ReportProgress(0, statusInfo);
                        Monitor.Wait(statusInfo);
                    }

                    do
                    {
                        var currentLink = row[2] + "&p=" + page;
                        var htmlWeb = new HtmlWeb();
                        var htmlDocument = htmlWeb.Load(currentLink);

                        const string trPath = "//table[@id='main']//table[@id='table2']//table[2]/tr[position()>1]";
                        trList = htmlDocument.DocumentNode.SelectNodes(trPath);

                        if (trList != null)
                        {
                            for (var i = 1; i <= trList.Count; i++, count++)
                            {
                                var isDownloaded = false;
                                var tdNodes = trList[i - 1].SelectNodes("td");
                                string message = "", orderNumber = "", duplicateName = "";

                                // td[0] - id, td[1] - title, td[2] - thể loại, td[3] - link
                                if (tdNodes != null)
                                {
                                    message = (count + 1) + ". " + tdNodes[1].InnerText;
                                    fileWriter.Write("{0}\t", tdNodes[1].InnerText);


                                    var linkNode = tdNodes[3].SelectSingleNode("a[@href]");
                                    var name = "";
                                    if (linkNode != null)
                                    {
                                        var link = linkNode.GetAttributeValue("href", "");
                                        name = link.Substring(link.LastIndexOf('/') + 1);

                                        if (name != "")
                                        {
                                            if (nameDict.ContainsKey(name))
                                                duplicateName = nameDict[name];
                                            else
                                            {
                                                nameDict.Add(name, (count + 1).ToString());
                                                isDownloaded = true;
                                                var runPath = "/a /n /p \"" + currentPath + "\" /d \"" + link + "\"";

                                                if (!existCheck.Checked)
                                                    ProcessLink(runPath, i, trList);
                                                else if (!File.Exists(currentPath + @"\" + name))
                                                    ProcessLink(runPath, i, trList);

                                            }
                                            nameList.Add(name);
                                        }
                                    }

                                    fileWriter.Write("{0}\t{1}\t", name, tdNodes[2].InnerText);

                                    if (titleDict.ContainsKey(tdNodes[1].InnerText))    // trùng title?
                                    {
                                        orderNumber = titleDict[tdNodes[1].InnerText];   // lấy stt
                                        duplicateDict.Add(tdNodes[1].InnerText, nameList[int.Parse(orderNumber) - 1]);
                                        duplicateDict.Add(tdNodes[1].InnerText, name);
                                    }
                                    else
                                    {
                                        titleDict.Add(tdNodes[1].InnerText, (count + 1).ToString());
                                    }

                                    fileWriter.Write("{0}\t{1}\t{2}", orderNumber, duplicateName,
                                                     isDownloaded ? "1" : "0");
                                }

                                fileWriter.Write(fileWriter.NewLine);
                                lock (statusInfo)
                                {
                                    statusInfo.Message = message;
                                    bgWorker.ReportProgress((int)(i * 100.0 / trList.Count), statusInfo);
                                    Monitor.Wait(statusInfo);
                                }
                            }
                        }
                        page++;
                    } while (trList != null);

                    fileWriter.Flush();
                    fileWriter.Close();

                    fileWriter = new StreamWriter(currentPath + @"\DupOf" + Path.GetFileName(e.Argument.ToString()), false,
                                                  Encoding.UTF8);

                    foreach (var item in duplicateDict.AllKeys)
                        fileWriter.WriteLine("{0},{1}", item, duplicateDict[item]);

                    fileWriter.Flush();
                    fileWriter.Close();

                    totalCount += count;
                }
            }
            catch (Exception ex)
            {
                lock (statusInfo)
                {
                    statusInfo.Message = ex.ToString();
                    bgWorker.ReportProgress(0, statusInfo);
                    Monitor.Wait(statusInfo);
                }
            }
            finally
            {
                if (fileWriter != null)
                    fileWriter.Close();
            }
        }

        private void ProcessLink(string runPath, int i, HtmlNodeCollection trList)
        {
            if (trList == null)
                return;

            if (addCheck.Checked)
            {
                Process.Start(idmText.Text, runPath);
                Thread.Sleep(20);
            }
            else
            {
                lock (statusInfo)
                {
                    statusInfo.Message = runPath;
                    bgWorker.ReportProgress((int)(i * 100.0 / trList.Count), statusInfo);
                    Monitor.Wait(statusInfo);
                }
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var si = e.UserState as StatusInfo;
            lock (statusInfo)
            {
                if (e.ProgressPercentage <= 0)
                {
                    if (statusInfo.CurrentIndexChanged)
                        try
                        {
                            listCombo.SelectedIndex = statusInfo.CurrentIndex;
                            linkText.Text = linkList[statusInfo.CurrentIndex][2];
                        }
                        catch (Exception ex)
                        {
                            messageText.AppendText(ex.Message + System.Environment.NewLine);
                        }
                }
                else
                {

                    progressBar.Value = e.ProgressPercentage;
                    messageText.AppendText(statusInfo.Message + System.Environment.NewLine);
                }
                statusInfo.Reset();
                Monitor.Pulse(statusInfo);
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar.Value = 0;
            progressBar.Visible = false;
            messageText.AppendText("Completed at " + DateTime.Now.ToString());
            messageText.AppendText("Total : " + totalCount.ToString());
        }

        private void openButton_Click(object sender, EventArgs e)
        {
            var ofd = new OpenFileDialog
                {
                    Filter = @"Comma-separator values|*.csv",
                    CheckFileExists = false,
                    AddExtension = true,
                    FileName = "ReportAt" + DateTime.Now.ToString("ddMMyyhhmm")
                };

            if (ofd.ShowDialog() == DialogResult.OK)
                reportLocationText.Text = ofd.FileName;
        }

        private void openLinkButton_Click(object sender, EventArgs e)
        {
            var ofd = new OpenFileDialog()
                {
                    Filter = @"Comma-separator values|*.csv",
                    CheckFileExists = true
                };


            if (ofd.ShowDialog() == DialogResult.OK)
            {
                var fileReader = new StreamReader(ofd.FileName, Encoding.UTF8);
                var currentLine = "";

                listCombo.Items.Clear();
                while ((currentLine = fileReader.ReadLine()) != null)
                {
                    var row = currentLine.Split('\t');

                    linkList.Add(row);
                    listCombo.Items.Add(row[0] + " - " + row[1]);
                }
            }
        }


        private void Crawler_Load(object sender, EventArgs e)
        {

        }
    }
}